import { Singleton } from "./Common";

export default class userEvent extends Singleton<userEvent>{

    private _handlers: { [name: string]: { handler: (...args: any)=>void, target: Object }[] } = {};

    protected onDestroy(){
        this._handlers = {};
    }

    public on(eventName: string, handler: (...args: any)=>void, target: Object):number {
        const objHandler = {handler: handler, target: target};
        let handlerList = this._handlers[eventName];
        if (!handlerList) {
            handlerList = [];
            this._handlers[eventName] = handlerList;
            handlerList.push(objHandler);
            return 1;
        }

        for (let i = handlerList.length - 1; i >= 0; --i) {
            if (!handlerList[i] || handlerList[i].target === target){
                handlerList[i] = objHandler;
                return i;
            } else {
                const obj = handlerList[i].target;
                // @ts-ignore
                if (obj && obj.target && !obj.target.isValid){
                    handlerList.splice(i,1);
                }
            }
        }

        handlerList.unshift(objHandler);
        return handlerList.length;
    }

    public emit (eventName: string, ...args: any) {
        const handlerList = this._handlers[eventName];

        if (!handlerList || handlerList.length < 1) {
            return ;
        }

        const params = [];
        for (let i = 1; i < arguments.length; ++i) {
            params.push(arguments[i]);
        }

        for (let i = 0; i < handlerList.length; ++i) {
            const obj = handlerList[i];
            if (obj && obj.handler && obj.target) {
                // @ts-ignore
                if (!obj.target.isValid){
                    handlerList.splice(i,1);
                    continue ;
                }
                obj.handler.apply(obj.target, args);
            }
        }
    }

    public off (eventName: string, target: Object) {
        const handlerList = this._handlers[eventName];

        if (!handlerList) {
            return;
        }

        for (let i = 0; i < handlerList.length; i++) {
            const oldObj = handlerList[i];
            if (oldObj && target === oldObj.target) {
                handlerList.splice(i, 1);
                return;
            }
        }
    }

    public offAll(target: Object) {
        if (!target) {
            return;
        }

        const keys = Object.keys(this._handlers);
        for (let k of keys){
            const handlerList = this._handlers[k];
            for (let i = 0; i < handlerList.length; i++) {
                const oldObj = handlerList[i];
                if (oldObj && target === oldObj.target) {
                    handlerList.splice(i, 1);
                    continue;
                }
            }
        }
    }
}